﻿#include <iostream>

#include "rotest.h"

#include "remoteobjectnode.h"
#include <remoteobjecthost.h>
#include "metafunction.h"
#include "dynamicremoteobject.h"

#include "variant.h"
#include "tcpsocket.h"
#include "eventloop.h"

#include "enumrate.h"
#include <RX3DWidget.h>

RemoteObjectHost* host = NULL;//服务器节点
ROTest* source = NULL;//原件


RemoteObjectNode* node = NULL;//客户端节点
ROTest* replica = NULL;//副本
DynamicRemoteObject* replica_d = NULL;//动态副本

void DynamicTest();
void StaticTest();

void InitSource() {//初始化原件
	source = new ROTest();

	MetaFunction meta = source->GetMetaInfo().GetFunction(source->GetMetaInfo().IndexOfFunction("Print(Variant)"));
	Variant v = Variant::FromValue(Variant(20));

	//为Number属性的变动信号连接槽
	source->NumberChanged.Bind([=](int number) {
		std::cout << "原件 Number属性改变了" << number << std::endl;
		});


	//初始化服务器节点
	RemoteObjectHost* host = new RemoteObjectHost();

	host->Listen("127.0.0.1:3036");

	host->enableRemoting(source);//将原件参与到共享中
}

void InitReplica() {//初始化副本
	//初始化客户端节点
	RemoteObjectNode* client = new RemoteObjectNode();

	client->connectTo("127.0.0.1:3036");//连接服务器节点

	replica = client->Acquire<ROTest>();//获取副本

	//为Number属性的变动信号连接槽
	replica->NumberChanged.Bind([=](int number) {
		std::cout << "副本 Number属性改变了" << number << std::endl;
		});

	//监听Clicked信号
	replica->Clicked.Bind([=](int i, double j) {
		std::cout << "原件发射了信号" << i << " " << j << std::endl;
		});

	//连接副本初始化信号
	replica->Initialized.Bind([=]() {
		StaticTest();
		});

}

void InitDynamicReplica() {//初始化副本
	//初始化客户端节点
	RemoteObjectNode* client = new RemoteObjectNode();

	client->connectTo("127.0.0.1:3036");//连接服务器节点

	replica_d = client->AcquireDynamic("ROTest");//获取副本

	//连接副本初始化信号
	//注意，动态远程对象还未初始化时并不具备原件的元信息，对于属性，信号和槽的获取只能移动到初始化完成后
	replica_d->Initialized.Bind([=]() {
		DynamicTest();
		});
}

void StaticTest() {
	std::cout << "副本初始化完成!" << std::endl;

	replica->SetNumber(20);//从副本设置属性值

	int ret = replica->Print(2000);//从副本调用Print函数
	std::cout << "调用结果" << ret << std::endl;


	source->Clicked(20, 30);//原件发射信号
}

void DynamicTest() {
	std::cout << "副本初始化完成!" << std::endl;

	//为Number属性的变动信号连接槽
	replica_d->GetRemoteSignal("NumberChanged(int)")->DownCast<int>()->Bind([](int number) {
		std::cout << "副本Number属性修改了" << number << std::endl;

		});

	replica_d->GetRemoteSignal("Clicked(int,double)")->DownCast<int, double>()->Bind(
		[](int i, double j) {
			std::cout << "原件发射了信号" << i << " " << j << std::endl;
		}
	);

	replica_d->SetRemoteProperty("Number", Variant(20));

	std::shared_ptr<WorkFuture<Variant>> future = replica_d->CallRemoteFunction("Print(Variant)", { 2000 });
	future->WaitForFinished(true);
	int ret = future->GetReturnValue().Value<int>();//从副本调用Print函数
	std::cout << "调用结果" << ret << std::endl;

	source->Clicked(20, 30);//原件发射信号
}

/*
待研发
1.动态副本(已完成)
2.自动状态维护
3.权限管理
4.子对象和远程对象指针
5.属性刷新方案
*/
#include <objecttrace.h>


/*
静态远程对象
缺点
1.服务端与客户端的远程对象类必须完全定义相同，参数变化或函数调换顺序都会导致无法通讯
优点：
使用方便
*/

class M
{

};

class N :public M{

};

class C {
public:
	N n;
};

void StaticReplicaTest() {

	InitSource();
	InitReplica();

	EventLoop loop;
	loop.exec();
}

/*
动态远程对象
缺点
使用麻烦，需要先从服务端获取元信息
优点：
不需要得知服务器端类定义信息，能够动态获取这些信息,不必保持版本一致
*/

void DynamicReplicaTest() {
	InitSource();
	InitDynamicReplica();

	EventLoop loop;
	loop.exec();
}

#include <Timer.h>
#include <objectserilize.h>

void SerilizeTest() {

	ROTest *ro = new ROTest();

	ro->SetNumber(2000);
	ro->SetName("1234");

	ObejctSerilize::RegisterSerilizer<ROTest>();

	ByteArray ret = ObejctSerilize::SerilizeObj(ro);

	ROTest *ro2 = new ROTest();

	ObejctSerilize::UnSerilizeObj(ret,ro2);

	int i = 0;
	i++;
}


class ET :public ThreadSafe::ThreadSafeBase {
public:
	~ET() {
		std::cout << "Deleted!" << std::endl;
	}
};

void EventTest() {
	ET* et = new ET();
	EventLoop loop;
	
	Signal<> Click;

	Click.Bind([]() {
		std::cout << "Clicked!" << std::endl;
	}, et);

	std::thread t([&]() {
		Click();
	});

	loop.exec();
}

#include <statemachine.h>

class ST :public ReflectableObject {
public:
	REFLECTABLE(ST, ReflectableObject);

	ST() {
		Number = 0;
	}

	void SetNumber(int v) {
		Number = v;
	}

	int GetNumber() const{
		return Number;
	}

	void Print(int) {
		
	}

	void Print(double) {

	}

private:
	int Number;

};

BeginMetaData(ST)

META_DefaultConstructor

META_BEGIN_PROPERTY(Number)
META_ADD_GETTER(GetNumber)
META_ADD_SETTER(SetNumber)
META_END_PROPERTY

META_BEGIN_FUNCTION_X(Print,int)
META_END_FUNCTION

META_BEGIN_FUNCTION_X(Print, double)
META_END_FUNCTION

EndMetaData



void StateMachineTest()
{
	StateMachine::StateMachine *machine = new StateMachine::StateMachine();

	ST* o = new ST();

	Signal<> Change;

	auto s1 = machine->CreateSubState();
	
	auto s11 = s1->CreateSubState();
	s11->SetProperty(o, "Number", 11);
	auto s12 = s1->CreateSubState();
	s12->SetProperty(o, "Number", 12);

	s1->SetInitState(s11);

	auto s2 = machine->CreateSubState();
	s2->SetProperty(o, "Number", 2);

	s11->AddTranslation(&Change, s12);
	s12->AddTranslation(&Change, s2);
	s2->AddTranslation(&Change, s11);

	s12->EnteredState.UnSafeBind([&](const void**) {
		Change();
	});

	s2->EnteredState.UnSafeBind([&](const void**) {
		Change();
	});

	machine->SetInitState(s1);

	machine->Start();

	Change();

	EventLoop loop;
	loop.exec();

	machine->Stop();
	delete machine;

}

#include <ObjectPool.h>

class W {
public:

	//bool operator == (const W& o)const {
	//	return i == o.i;
	//}

	int P(int i) {
		std::cout << 1 << std::endl;
	}

	int P(double i) {
		std::cout << 2 << std::endl;
	}

	int i;
};

#include <stringutil.h>

#include <shareddata.h>

//class BlockData {
//public:
//	int number;
//};

//class Block {
//public:

//	int GetNumber() const {
//		return d->number;
//	}

//	void SetNumber(int n) {
//		d->number = n;
//	}

//private:
//	SharedDataPointer<BlockData> d;
//};

//#include <GlobalSymbol.h>

//static BlockData* GetInstance() {
//	static auto ret = GLOBAL_SYMBOL_ACQUIRE(BlockData, blockDataInstance);

//	return ret.get();
//}




using namespace ThreadSafe;
class A : public ThreadSafeBase
{
public:
	int a_ = 10;
	void print()
	{
		fprintf(stdout, "ZJF %s:%d a=%d\n", __func__, __LINE__, a_);
	}
	A() {
		fprintf(stdout, "ZJF %s:%d \n", __func__, __LINE__);
	}
	~A() {
		fprintf(stdout, "ZJF %s:%d \n", __func__, __LINE__);
	}
};
#include <thread>
void func1(A* a)
{
	EventLoop::PostEvent((ThreadSafeBase*)a, new ThreadSafe::InvokeFunctionEvent([&]() {
		fprintf(stdout, "ZJF %s:%d \n", __func__, __LINE__);
		 fprintf(stdout, "ZJF %s:%d 收到事件a=%d\n", __func__, __LINE__, a->a_);
		 a->print();
		}));
}

#include <threadpool.h>

#include <RXWorld.h>
#include <RXShadowWorld/RXAspectEngine.h>
#include <FrameAspect/FrameAspect.h>
#include <FrameAspect/FrameComponent.h>
#include <RXBasicAspect/RXBasicAspect.h>
#include <RXEntity.h>
#include <Eigen/Eigen>
#include <QApplication>
#include <RXTypes.h>
#include <IUCompress.h>
#include <bytearraystream.h>
#include <IUString.h>
#include <fstream>
#include <metaconstructor.h>
#include <stringapiset.h>

int print(int i, double j) {
	std::cout << i << " " << j;
	return i;
}

struct Test
{
	int operator()(int i, double j) {
		std::cout << i << " " << j;
		return i;
	}

	volatile int print(int i,double j) {
		std::cout <<"non const" << i << " " << j;
		return i;
	}

	volatile int print(int i, double j) const {
		std::cout << "const" << i << " " << j;
		return i;
	}

	int k;
};

#include <metaproperty.h>
int main(int argc, char *argv[])
{
	MetaInfo meta = ROTest::staticMetaInfo();

	int index = meta.IndexOfConstructor("ROTest()");
	MetaConstructor con = meta.GetConstructor(index);

	ROTest* test = (ROTest*)con.Create(NULL);

	//int fIndex = meta.IndexOfFunction("Say()");
	//MetaFunction fun = meta.GetFunction(fIndex);

	//fun.Invoke(test, (void*)NULL,1);
	
	int pIndex = meta.IndexOfProperty("ID");
	MetaProperty pro = meta.GetProperty(pIndex);
	pro.SetValue(test, 1.0);
	Variant v = pro.GetValue(test);
	int val = v.Value<double>();
	bool Static = pro.isStatic();
	/*MetaType::IdFromType<std::vector<double>>();*/
	



	int i = -1.1;
	std::cout << i;

	//Image image(Image::ST_UINT8, 4, { 32,32 });
	//auto data = image.GetData();
	//
	//for (auto i = 0; i < 32 * 32; i++)
	//{
	//	auto p = data + i * 4;
	//	p[0] = 0xff;
	//	p[1] = 0xFF;
	//	p[2] = 0x0;
	//	p[3] = 0X0;
	//}

	//BytearrayOutputStream btaStream;
	//DataOutputStream dataStream(&btaStream);
	//dataStream << image;

	//auto ret = btaStream.GetByteArray();

	//
	//BytearrayInputStream biStream(ret.data(), ret.size());
	//DataInputStream dataIStream(&biStream);
	//dataIStream >> image;

	//std::cout << ret.size() << std::endl;

	auto codec = IUStringUtils::CreateCodec("local");

	const char name[] = "你好世界";

	auto d = codec->Decode(IUByteArray((const unsigned char*)name, (const unsigned char*)name + sizeof(name) - 2));

	

	//std::fstream file;

	//file.open("D:\\Users\\Desktop\\name.txt", std::ios::out | std::ios::binary);

	//file.write((const char*)d.data(), d.size());
	

	//Image::ToFile(image,"D:\\Users\\Desktop\\imageTest.png");

	//QApplication app(argc,argv);
	//RX3DWidget widget;
	//widget.show();


	//return app.exec();
	{
		/*ROTest* test = new ROTest();

		auto meta = test->GetMetaInfo();

		auto fun = meta.GetFunction(meta.IndexOfFunction("PR(PT)"));
		PT p;
		fun.Invoke(test, (void*)NULL, p);*/
		
		Signal<PT> s;
		s.Bind([](const PT& p) {
			std::cout << 123<<std::endl;
		});
		PT p;
		s(p);

		return 0;
	}
	//RXAspectEngine* engine = new RXAspectEngine({new FrameAspect(),new RXBasicAspect() });

	//RXEntity* root = new RXEntity();

	//FrameComponent* comp = new FrameComponent();

	//comp->SetParent(root);

	//engine->GetWorld()->SetRootEntity(root);
	//
	//comp->OnFrame.Bind([=](double time) {
	//	std::cout << time << std::endl;
	//});

	//ReflectableObject o;

	//auto now = std::chrono::system_clock::now();

	//Timer::SingleShot(std::chrono::system_clock::now() + std::chrono::milliseconds(5), [=]() {std::cout << (std::chrono::system_clock::now() - now).count() << std::endl; }, &o);

	EventLoop loop;
	loop.exec();

	return 0;
	//ThreadPool pool(2,5,ThreadPool::IncreseOnNeed);

	//ThreadJobPtr j1 = ThreadJob::CreateJob([]() {
	//	std::this_thread::sleep_for(std::chrono::seconds(1));
	//	std::cout << "Job1"<<std::endl;
	//	});

	//ThreadJobPtr j2 = ThreadJob::CreateJob([]() {
	//	std::this_thread::sleep_for(std::chrono::seconds(1));
	//	std::cout << "Job2" << std::endl;
	//	}, {j1});

	//ThreadJobPtr j3 = ThreadJob::CreateJob([]() {
	//	std::this_thread::sleep_for(std::chrono::seconds(1));
	//	std::cout << "Job3" << std::endl;
	//	}, {j1});

	//ThreadJobPtr j4 = ThreadJob::CreateJob([]() {
	//	std::this_thread::sleep_for(std::chrono::seconds(1));
	//	std::cout << "Job4" << std::endl;
	//	}, {j2,j3});

	//WorkCondition cond;
	//cond.AddWork();
	//ThreadJobPtr count = ThreadJob::CreateJob([&]() {
	//	std::this_thread::sleep_for(std::chrono::seconds(1));
	//	std::cout << "Finished!" << std::endl;
	//	cond.FinishWork();
	//	}, {j4});
	//

	//pool.PostJob({ count ,j2,j1,j4,j3});//随便哪个顺序投入任务

	//cond.WaitForFinished();
	//pool.stop();

	//DynamicReplicaTest();


	//ReflectableObject obj;//假设这是一个要接收通知的对象
	//obj.MoveToThread(std::this_thread::get_id());//让它工作在主线程

	//auto handle = [&]() {
	//	std::cout << "hello world" << std::endl;//这是接收回调函数后经历的一系列处理,因为事件循环的因故，它会在主线程执行
	//};

	//std::thread([&]() {//假设某个线程执行了回调函数
	//	//在回调函数内部通过事件循环向对象发送事件
	//	EventLoop::PostEvent(&obj, new ThreadSafe::InvokeFunctionEvent(handle));
	//});


	//EventLoop loop;//创建事件循环
	//loop.exec();//执行事件循环，代码会卡在这个地方，一直不停的接收外部信息


	////StateMachineTest();
	//ST* o = new ST();
	////auto info = o->GetMetaInfo();
	//Reflectable* t = NULL;
	//
	////auto s = MetaType::__GetNameFromType<ST*>::Get();
	//Variant v = Variant::FromValue(o);
	//t = v.Value<Reflectable*>();


	//auto meta = ST::staticMetaInfo();
	
	//Block b1, b2;

	//b1.SetNumber(20);
	//b2 = b1;

	//b2.SetNumber(40);

	//MetaType type = MetaType::IdFromType<intMap>();

	return 0;
}
